package vg.modules.graph_settings;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxUtils;

import vg.services.graph_view_manager.interfaces.graph_view.AGraphView;
import vg.services.graph_view_manager.interfaces.graph_view.IGraphSettings;
import vg.services.graph_view_manager.interfaces.tab.ATab;
import vg.services.main_manager.MainManager;
import vg.services.plugin_manager.event_and_request.event.AUIEvent;
import vg.services.plugin_manager.event_and_request.event.UIEventCloseTab;
import vg.services.plugin_manager.event_and_request.event.UIEventOpenNewTab;
import vg.services.plugin_manager.interfaces.IPlugin;
import vg.services.plugin_manager.realization.PluginParameter;
import vg.services.user_interface_manager.additional_swing_components.FontChooserComboBox;
import vg.services.user_interface_manager.interfaces.AMenuItem;

public class GraphSettingsPlugin implements IPlugin{	
	// Main data
	private boolean inited = false;
	private int 	spacingLeft;
	private int 	spacingTop;
	private int 	spacingRight;
	private int 	spacingBottom;
	
	private String 	fontColor;
	private String 	fillColor;
	private String 	vertexShape;
	private String 	graphElemetsFont;
	private String 	vertexTextAlign;
	
	private Map<Integer, ATab> tabs = new HashMap<Integer, ATab>();
	
	// Swing components
	private JComponent[] dialogComponents = null;
	private FontChooserComboBox fontChooser = null;
	private IntegerDocumentListner spacingLeftDoc = null;
	private IntegerDocumentListner spacingTopDoc = null;
	private IntegerDocumentListner spacingBottomDoc = null;
	private IntegerDocumentListner spacingRightDoc = null;
	private ColorPreview fontColorPreview = null;
	private ColorPreview vertexColorPreview = null;
	private JRadioButton leftAlignRadio = null;
	private JRadioButton centerAlignRadio = null;
	private JRadioButton rightAlignRadio = null;
	private JComboBox shapeList = null;
	
	/**
	 * Constructor.
	 */
	public GraphSettingsPlugin() {
		spacingBottom = 0;
		spacingTop = 0;
		spacingLeft = 0;
		spacingRight = 0;
		fontColor = "black";
		fillColor = "white";
		vertexShape = mxConstants.SHAPE_RECTANGLE;
		graphElemetsFont = "Monospaced";
		vertexTextAlign = mxConstants.ALIGN_LEFT;
		loadSettings();
	}
	
	@Override
	public void install(PluginParameter parameter) throws Exception {
		JMenuItem graphSettings = new JMenuItem("Graph settings");
		graphSettings.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (!inited)
					init();
				for (JComponent c: dialogComponents) {
					SwingUtilities.updateComponentTreeUI(c);
				}

				if (JOptionPane.showConfirmDialog(null, dialogComponents, "Graph visualization settings", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == 0) {
					String fontName = fontChooser.getSelectedFontName();
					if (fontName != null)
						graphElemetsFont = fontName;
					spacingLeft = spacingLeftDoc.getValue();
					spacingTop = spacingTopDoc.getValue();
					spacingRight = spacingRightDoc.getValue();
					spacingBottom = spacingBottomDoc.getValue();
					fontColor = mxUtils.hexString(fontColorPreview.getBackground());
					fillColor = mxUtils.hexString(vertexColorPreview.getBackground());
					if (leftAlignRadio.isSelected()) {
						vertexTextAlign = mxConstants.ALIGN_LEFT;
					} else if (centerAlignRadio.isSelected()) {
						vertexTextAlign = mxConstants.ALIGN_CENTER;
					} else if (rightAlignRadio.isSelected()) {
						vertexTextAlign = mxConstants.ALIGN_RIGHT;
					}
					vertexShape = shapeList.getSelectedItem().toString();
					
					// save settings
					saveSettings();
					
					// apply settings to exist graph views
					for (ATab bufTab : tabs.values()) {
						if (bufTab.getTabType() == ATab.DEF_GRAPH_VIEW_TAB_TYPE) {
							AGraphView graph_view = (AGraphView)bufTab;
							graph_view.getGraphSettings().setStyle(generateStyleSheet());
						}
					}
				}
			}
		});
		
		parameter.userInterface.addMenuItem(new AMenuItem(graphSettings) {
			public void update(Observable o, Object arg) {
				if(arg instanceof AUIEvent) {
					AUIEvent event = (AUIEvent)arg;
					switch(event.getType()) {
						case DEF_OPEN_NEW_TAB: {
							UIEventOpenNewTab def_event = (UIEventOpenNewTab)event;
							tabs.put(def_event.getTabId(), def_event.getTab());
							break;
						}
						case DEF_CLOSE_TAB: {
							UIEventCloseTab def_event = (UIEventCloseTab)event;
							tabs.remove(def_event.getTabId());							
							break;
						}
						case DEF_CHANGE_UI_STYLE: {
							// TODO
							break;
						}
						default: break;
					}
				}
			}
		}, "edit");
	}
	
//=============================================================================
//-----------------PRIVATE METHODS---------------------------------------------
	private void loadSettings() {
		String tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_LEFT);
		if (tmp != null) {
			spacingLeft = Integer.valueOf(tmp);
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_TOP);
		if (tmp != null) {
			spacingTop = Integer.valueOf(tmp);
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_RIGHT);
		if (tmp != null) {
			spacingRight = Integer.valueOf(tmp);
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_BOTTOM);
		if (tmp != null) {
			spacingBottom = Integer.valueOf(tmp);
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_FONT_COLOR);
		if (tmp != null) {
			fontColor = tmp;
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_FILL_COLOR);
		if (tmp != null) {
			fillColor = tmp;
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_SHAPE);
		if (tmp != null) {
			vertexShape = tmp;
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_VERTEX_TEXT_ALIGN);
		if (tmp != null) {
			vertexTextAlign = tmp;
		}
		tmp = MainManager.config.getProperty(IGraphSettings.DEF_STYLE_GRAPH_ELEMENTS_FONT);
		if (tmp != null) {
			graphElemetsFont = tmp;
		}
	}
	
	private Map<String, Object> generateStyleSheet() {
		Map<String, Object> style = new HashMap<String, Object>();
		
		style.put(mxConstants.STYLE_SHAPE, vertexShape);
		style.put(mxConstants.STYLE_FONTCOLOR, fontColor);
		style.put(mxConstants.STYLE_FILLCOLOR, fillColor);
		style.put(mxConstants.STYLE_SPACING_LEFT, spacingLeft);
		style.put(mxConstants.STYLE_SPACING_RIGHT, spacingRight);
		style.put(mxConstants.STYLE_SPACING_TOP, spacingTop);
		style.put(mxConstants.STYLE_SPACING_BOTTOM, spacingBottom);
		style.put(mxConstants.STYLE_ALIGN, vertexTextAlign);
		style.put(mxConstants.STYLE_FONTFAMILY, graphElemetsFont);
		
		style.put(mxConstants.STYLE_FONTFAMILY, graphElemetsFont);
		style.put(mxConstants.STYLE_ENDARROW, mxConstants.ARROW_CLASSIC);
		style.put(mxConstants.STYLE_ROUNDED, "1");
		
		return style;
	}
		
	private void saveSettings() {
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_GRAPH_ELEMENTS_FONT, graphElemetsFont);
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_FILL_COLOR, fillColor);
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_FONT_COLOR, fontColor);
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_SHAPE, vertexShape);
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_TEXT_ALIGN, vertexTextAlign);
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_BOTTOM, String.valueOf(spacingBottom));
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_TOP, String.valueOf(spacingTop));
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_LEFT, String.valueOf(spacingLeft));
		MainManager.config.setProperty(IGraphSettings.DEF_STYLE_VERTEX_SPACING_RIGHT, String.valueOf(spacingRight));
	}
	
	private void init() {
		if (inited)
			return;
		
		loadSettings();
		
		this.fontChooser = new FontChooserComboBox(MainManager.threadPool, graphElemetsFont);
		
		this.fontColorPreview = new ColorPreview();
		fontColorPreview.setBackground(mxUtils.parseColor(fontColor));
		
		JButton fontColorButton = new JButton("change");
		fontColorButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				Color newColor = JColorChooser.showDialog(null, "Set font color", fontColorPreview.getBackground());
				if (newColor != null) {
					fontColorPreview.setBackground(newColor);
				}
			}
		});

		JPanel colorFontPane = new JPanel();
		colorFontPane.setLayout(new BoxLayout(colorFontPane, BoxLayout.X_AXIS));
		colorFontPane.add(new JLabel("Font color"));
		colorFontPane.add(Box.createHorizontalGlue());
		colorFontPane.add(fontColorPreview);
		colorFontPane.add(Box.createRigidArea(new Dimension(5,0)));
		colorFontPane.add(fontColorButton);
		
		JPanel vertexSpacing = new JPanel();
		vertexSpacing.setBorder(BorderFactory.createTitledBorder("Vertex spacing"));
		vertexSpacing.setLayout(new GridBagLayout());
		
		GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST,
				GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0);
		vertexSpacing.add(new JLabel("Left"), gbc);
		
		gbc = new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST,
				GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0);
		JTextField tf = new JTextField();
		tf.setText(String.valueOf(spacingLeft));
		this.spacingLeftDoc =  new IntegerDocumentListner(tf, spacingLeft);
		tf.getDocument().addDocumentListener(this.spacingLeftDoc);
		vertexSpacing.add(tf, gbc);
		
		gbc = new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.NORTHWEST,
				GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0);
		vertexSpacing.add(new JLabel("Top"), gbc);
		
		gbc = new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.NORTH,
				GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0);
		tf = new JFormattedTextField();
		tf.setText(String.valueOf(spacingTop));
		this.spacingTopDoc =  new IntegerDocumentListner(tf, spacingTop);
		tf.getDocument().addDocumentListener(this.spacingTopDoc);
		vertexSpacing.add(tf, gbc);
		
		gbc = new GridBagConstraints(0, 2, 1, 1, 1, 0, GridBagConstraints.NORTHWEST,
				GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0);
		vertexSpacing.add(new JLabel("Right"), gbc);
		
		gbc = new GridBagConstraints(1, 2, 1, 1, 1, 0, GridBagConstraints.NORTH,
				GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0);
		tf = new JFormattedTextField();
		tf.setText(String.valueOf(spacingRight));
		this.spacingRightDoc =  new IntegerDocumentListner(tf, spacingRight);
		tf.getDocument().addDocumentListener(this.spacingRightDoc);
		vertexSpacing.add(tf, gbc);
		
		gbc = new GridBagConstraints(0, 3, 1, 1, 1, 0, GridBagConstraints.NORTHWEST,
				GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0);
		vertexSpacing.add(new JLabel("Bottom"), gbc);
		
		gbc = new GridBagConstraints(1, 3, 1, 1, 1, 0, GridBagConstraints.NORTH,
				GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0);
		tf = new JFormattedTextField();
		tf.setText(String.valueOf(spacingBottom));
		this.spacingBottomDoc =  new IntegerDocumentListner(tf, spacingBottom);
		tf.getDocument().addDocumentListener(this.spacingBottomDoc);
		vertexSpacing.add(tf, gbc);
		
		this.vertexColorPreview = new ColorPreview();
		this.vertexColorPreview.setBackground(mxUtils.parseColor(fillColor));
		
		JButton vertexColorButton = new JButton("change");
		vertexColorButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				Color newColor = JColorChooser.showDialog(null, "Set font color",
						vertexColorPreview.getBackground());
				if (newColor != null) {
					vertexColorPreview.setBackground(newColor);
				}
				
			}
		});

		JPanel vertexColorPane = new JPanel();
		vertexColorPane.setLayout(new BoxLayout(vertexColorPane, BoxLayout.X_AXIS));
		vertexColorPane.add(new JLabel("Default vertex color"));
		vertexColorPane.add(Box.createHorizontalGlue());
		vertexColorPane.add(this.vertexColorPreview);
		vertexColorPane.add(Box.createRigidArea(new Dimension(5,0)));
		vertexColorPane.add(vertexColorButton);
		
		JPanel textAlignPane = new JPanel();
		textAlignPane.setLayout(new BoxLayout(textAlignPane, BoxLayout.X_AXIS));
		textAlignPane.setBorder(BorderFactory.createTitledBorder("Vertex text align"));
		this.leftAlignRadio = new JRadioButton("left",
				vertexTextAlign.equals(mxConstants.ALIGN_LEFT));
		this.centerAlignRadio = new JRadioButton("center",
				vertexTextAlign.equals(mxConstants.ALIGN_CENTER));
		this.rightAlignRadio = new JRadioButton("right",
				vertexTextAlign.equals(mxConstants.ALIGN_RIGHT));
		textAlignPane.add(this.leftAlignRadio);
		textAlignPane.add(Box.createHorizontalGlue());
		textAlignPane.add(this.centerAlignRadio);
		textAlignPane.add(Box.createHorizontalGlue());
		textAlignPane.add(this.rightAlignRadio);
		
		ButtonGroup group = new ButtonGroup();
		group.add(leftAlignRadio);
		group.add(centerAlignRadio);
		group.add(rightAlignRadio);
		
		this.shapeList = new JComboBox(new Object[] {
				mxConstants.SHAPE_RECTANGLE,
				mxConstants.SHAPE_ELLIPSE,
				mxConstants.SHAPE_DOUBLE_ELLIPSE,
				mxConstants.SHAPE_RHOMBUS,
				mxConstants.SHAPE_CYLINDER,
				mxConstants.SHAPE_TRIANGLE,
				mxConstants.SHAPE_HEXAGON,
				mxConstants.SHAPE_CLOUD
		});
		
		dialogComponents = new JComponent[] { 
				new JLabel("Font"), 
				fontChooser, 
				colorFontPane,
				vertexSpacing, 
				vertexColorPane,
				textAlignPane,
				new JLabel("Default vertex shape"),
				shapeList
		};
		inited = true;
	}
	
	private class IntegerDocumentListner implements DocumentListener {
		private JTextField tf;
		private int value;
		
		public IntegerDocumentListner(JTextField textField, int oldvalue) {
			tf = textField;
			value = oldvalue;
		}
		
		public void removeUpdate(DocumentEvent e) {
			String str = tf.getText();
			if (str != null && str.length() > 0) {
				try {
					value = Integer.parseInt(str);
				} catch (NumberFormatException e1) {
					SwingUtilities.invokeLater(new Runnable() {
						public void run() {
							tf.setText(String.valueOf(value));
							tf.repaint();
						}
					});
				}
			} else {
				value = 0;
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						tf.setText(String.valueOf(value));
						tf.repaint();
					}
				});
			}

			
		}
		public void insertUpdate(DocumentEvent e) {
			removeUpdate(e);
		}
		public void changedUpdate(DocumentEvent e) {
			
		}
		
		public int getValue() {
			return value;
		}
	}
	
	private class ColorPreview extends JComponent {
		private static final long serialVersionUID = -2276526078891878352L;
		ColorPreview() {
			setMinimumSize(new Dimension(24,24));
			setPreferredSize(getMinimumSize());
			setMaximumSize(getPreferredSize());
		}
		@Override
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			g.setColor(new Color(0,0,0));
			Rectangle bg = new Rectangle(0, 0, getWidth(), getHeight());
			bg = bg.intersection(g.getClipBounds());
			g.fillRect(bg.x, bg.y, bg.width, bg.height);
			
			g.setColor(getBackground());
			bg = new Rectangle(1, 1, getWidth() - 2, getHeight() - 2);
			bg = bg.intersection(g.getClipBounds());
			g.fillRect(bg.x, bg.y, bg.width, bg.height);
		}
	}
}

